package com.googlecode.openrtp.grizzly.rtcp;

import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import com.googlecode.openrtp.grizzly.ThreadResources;
import com.googlecode.openrtp.grizzly.session.DelayedSession;
import com.googlecode.openrtp.grizzly.session.SessionContextListener;
import com.googlecode.openrtp.spi.RtpSession;
import com.googlecode.openrtp.spi.SessionKeys;

/**
 *
 * @author jocke
 */
@Singleton
public final class RtcpManager implements SessionContextListener {

    private static final DelayQueue DELAY_QUEUE = new DelayQueue();

    @Inject
    public RtcpManager(ThreadResources threadResources) {
        RtcpSenderNotifier rtcpSenderNotifier = new RtcpSenderNotifier();
        threadResources.getScheduledThreadPool().scheduleWithFixedDelay(rtcpSenderNotifier, 1, 1, TimeUnit.SECONDS);
    }

    @Override
    public void sessionAdded(RtpSession session) {
        session.set(SessionKeys.NEXT_RTCP_TRANSMISSION, getNextTransmission());
        DELAY_QUEUE.add(new DelayedSession(SessionKeys.NEXT_RTCP_TRANSMISSION, session));
    }

    @Override
    public void sessionRemoved(RtpSession session) {
        DELAY_QUEUE.remove(new DelayedSession(SessionKeys.NEXT_RTCP_TRANSMISSION, session));
    }

    private long getNextTransmission() {
        return TimeUnit.SECONDS.toNanos(5) + System.nanoTime();
    }

    private final class RtcpSenderNotifier implements Runnable {

        private final List<DelayedSession> delayedSessions;

        public RtcpSenderNotifier() {
            delayedSessions = new ArrayList<>();
        }

        @Override
        public void run() {
            DELAY_QUEUE.drainTo(delayedSessions);
            for (DelayedSession delayedSession : delayedSessions) {
                delayedSession.getPacketGenerator().generateRtcpPacket();
                delayedSession.getSession().set(
                        SessionKeys.NEXT_RTCP_TRANSMISSION,
                        getNextTransmission());
                DELAY_QUEUE.offer(delayedSession);
            }
            delayedSessions.clear();
        }
    }
}
